import axios from 'axios'
const cancelToken = axios.CancelToken
import errorMessages from './errorMessages'

export class Instance {
  /**
   * axios实例参数配置
   * @param {*} config
   * config = {
   *   baseURL: process.env.VUE_APP_BASE_API,
   *   withCredentials: true,
   *   timeout: 5000
   * }
   */
  constructor(config) {
    /**
      声明一个数组用于存储每个ajax请求的取消函数和ajax标识
     */
    this.pending = {}

    this.removePending = this.removePending.bind(this)

    this.axiosInstance = this.createdInstance(config)
    this.interceptorsRequest()
    this.interceptorsRespose()
  }

  /**
   * 取消请求
   * @param {Object} config 请求拦截的config
   */
  removePending(config) {
    const that = this
    const requestKey = `${config.url}&${config.method}`
    for (const k in that.pending) {
      const cancel = that.pending[k]

      if (k === requestKey) {
        cancel() // 执行取消操作
        delete that.pending[requestKey] // 把这条记录从数组中移除
      }
    }
  }

  // 创建axios实例
  createdInstance(config) {
    return axios.create(config)
  }

  // 请求拦截处理
  interceptorsRequest() {
    const that = this
    this.axiosInstance.interceptors.request.use(
      // 你可以在这里定制一些全局参数
      (config) => {
        // 在一个ajax发送前执行一下取消操作
        that.removePending(config)

        /**
         * 存储请求列表，在必要时，可以进行阻止请求操作
         */
        config.cancelToken = new cancelToken((cancel) => {
          const requestKey = `${config.url}&${config.method}`
          that.pending[requestKey] = cancel
        })
        return config
      },
      // 对错误进行一些处理
      (error) => {
        return Promise.reject(error)
      }
    )
  }

  // 添加响应拦截器
  interceptorsRespose() {
    let that = this
    this.axiosInstance.interceptors.response.use(
      (response) => {
        // 在一个ajax响应后再执行一下取消操作，把已经完成的请求从pending中移除
        that.removePending(response.config)
        // 2xx 范围内的状态码都会触发该函数。
        // 对响应数据做点什么
        return response
      },
      (error) => {
        // 超出 2xx 范围的状态码都会触发该函数。
        // 对响应错误做点什么
        if (error && error.response) {
          error.message =
            errorMessages[error.response.status] ||
            `连接错误${error.response.status}`
        } else {
          error.message = '连接到服务器失败'
        }
        return Promise.reject(error)
      }
    )
  }
}
